package personnel.department.utils;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang3.tuple.Pair;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.DateTime;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.Widget;

import personnel.department.dao.entity.UniqueObject;
import personnel.department.pages.widgets.AbstractWidget;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;

public class TranslatorUtils {
	
	public static Map<String, String> fieldsTranslator = ImmutableMap.<String, String>builder()
			.put("numberContract", "Номер контракта")
			.put("series", "Серия")
			.put("numberPasport", "Номер паспорта")
			.put("issuedBy", "Выдан")
			.put("dateIssued", "Дата выдачи")
			.put("numberCertificate", "Номер сертификата")
			.put("speciality", "Специальность")
			.put("assignmentCertificate", "Дата присвоения")
			.put("firstCertificate", "Первичный сертификат")
			.put("numberDiplom", "Номер диплома")
			.put("trainingPeriod", "Период обучения")
			.put("kmn", "Кандидат медицинских наук")
			.put("dmn", "Доктор медицинских наук")
			.put("faculty", "Факультет")
			.put("obtainment", "Дата получения")
			.put("startEducation", "Начало обучения")
			.put("finishEducation", "Конец обучения")
			.put("firstQualification", "Первая квалификация")
//			.put("medicDiplom", "Диплом о медобразовании")
			.put("surname", "Фамилия")
			.put("firstName", "Имя")
			.put("secondName", "Отчество")
			.put("post", "Должность")
			.put("notes", "Примечание")
			.put("internship", "Интернатура")
			.put("targetTraining", "Целевая подготовка")
			.put("inn", "ИНН")
			.put("snils", "СНИЛС")
			.put("pasport", "Паспорт")
			.put("recordService", "Трудовая книжка")
			.put("organization", "Организация")
			.put("nameCycle", "Название цикла")
			.put("whereCompleted", "Где пройдено")
			.put("hours", "Часы")
			.put("dateTesting", "Дата тестирования")
			.put("employee", "Работник")
			.put("dateQuit", "Дата увольнения")
			.put("numberOrder", "Номер приказа")
			.put("causeOfQuit", "Причина увольнения")
			.put("work", "Работа")
			.put("numberRecordService", "Номер трудовой книги")
			.put("dateRetraining", "Дата")
			.put("subdivisionName", "Структурное подразделение")
			.put("verification", "Дата подтверждения")
			.put("subdivision", "Структурное подразделение")
			.put("rate", "Ставка")
			.put("assigmentDate","Дата присвоения")
			.put("dateOfAssigment","Дата присвоения")
			.put("confirmation", "Дата подтверждения")
			.put("firstCategory", "Первая категория")
			.put("secondCategory", "Вторая категория")
			.put("higherCategory", "Высшая категория")
			.put("baseWork", "Основная")
			.put("externalWork", "Внешнее совместительство")
			.put("internalWork", "Внутреннее совместительство")
			.put("certificates", "Сертификаты")
			.put("medicPersonal", "Средний персонал")
			.put("qualifications", "Квалификации")
			.put("retraining", "Повышения квалификации")
			.put("validations", "Аттестации")
			.put("quits", "Увольнения")
			.put("causeOfTranslation", "Причина перевода")
			.put("assignmentDate", "Дата присвоения")
			.put("diplomNumber", "Номер диплома")
			.put("type", "Вид должности")
			.put("traineeship", "Ординатура")
			.put("medicPolic", "Медицинский полис")
			.build();

	public static Map<String, String> classTranslator = ImmutableMap.<String, String>builder()
			.put("AdoptedToStructural", "Принят в структурное подразделение")
			.put("Certificate", "Сертификат")
			.put("Degree", "Ученая степень")
			.put("Diplom", "Диплом")
			.put("Employee", "Сотрудник")
			.put("Internship", "Интернатура/ординатура")
			.put("Pasport", "Паспорт")
			.put("PersonalData", "Персональные данные")
			.put("Qualification", "Квалификация")
			.put("Quit", "Увольнение")
			.put("RecordService", "Трудовая книга")
			.put("Retraining", "Переподготовка")
			.put("StructualSubdivision", "Структурное подразделение")
			.put("SubsequentСertificate", "Последующий сертификат")
			.put("Translation", "Переведен в другое отделение")
			.put("Validation", "Аттестация")
			.put("Work", "Работа")
			.put("WorkType", "Тип работы")
			.put("EmployeeType", "Тип должности")
			.build();

	public static Map<String, String> personalTranslator = ImmutableMap.<String, String>builder()
			.put("surname", "Фамилия")
			.put("numberPasport", "Номер паспорта")
			.put("numberDiplom", "Номер диплома")
			.put("numberRecordService", "Номер трудовой книги")
			.put("subdivision", "Структурное подразделение")
			.put("inn", "ИНН")
			.build();
	
	public static List<String> titleForCombo = Lists.newArrayList("Тип должности", "Работа");
	


	public static List<Field> getTranslatorFields(Set<Field> fields) {
		return getTranslatorFields(fields, fieldsTranslator);
	}

	public static List<Field> getTranslatorFields(Set<Field> fields, Map<String, String> translator) {
		List<Field> translatorFields = Lists.newArrayList();
		for (Field field : fields) {
			if (translator.get(field.getName()) != null) {
				translatorFields.add(field);
			}
		}
		return translatorFields;
	}
	
	public static List<Field> getTranslatorFields(Field[] fields, Map<String, String> translator) {
		return getTranslatorFields(Sets.newHashSet(fields), translator);
	}

	private static List<Field> getTranslatorFields(Field[] fields,  boolean isWithIncludeFields, Class<?>... exClasses) {
		Set<Field> translatorFields = Sets.newLinkedHashSet(Arrays.asList(fields));
		if (isWithIncludeFields) {
			addIncludeFields(fields, translatorFields, exClasses);
		}
		return getTranslatorFields(translatorFields);
	}

	private static void addIncludeFields(Field[] fields,
			Set<Field> translatorFields, Class<?>... exClasses) {
		List<Class<?>> classes = Lists.newArrayList(exClasses);
		for (Field field : fields) {
			if (classes.contains(field.getType())) {
				translatorFields.remove(field);
				continue;
			}

			if (isAssignableOfUniqueObject(field.getType()) || field.getGenericType() instanceof ParameterizedType ) {
				Class<?> clazz = isAssignableOfUniqueObject(field.getType()) ? field.getType() : 
					ReflectionUtils.getGenericClass(field.getGenericType());

				translatorFields.remove(field);
				addIncludeFields(clazz.getDeclaredFields(), translatorFields, field.getDeclaringClass());
			} else {
				if (!translatorFields.contains(field)) {
					translatorFields.add(field);
				}
			}
		}
	}

	private static boolean isAssignableOfUniqueObject(Class<?> clazz) {
		return ReflectionUtils.isAssignableOfUniqueObject(clazz);
	}

	public static List<Field> getTranslatorFields(Field[] fields) {
		return getTranslatorFields(fields, Class.class);
	}

	public static String getClassName(String className) {
		return classTranslator.get(className);
	}

	public static List<Field> getTranslatorFields(Field[] fields,
			Class<?>... clazz) {
		return getTranslatorFields(fields, true, clazz);
	}

	public static List<String> certificateFields = ImmutableList.of(
			"series",
			"speciality",
			"numberCertificate", 
			"assignmentCertificate", 
			"confirmation", 
			"firstCertificate"
			);

	public static List<String> adoptedToStructuralFields = ImmutableList.of(
			"numberContract",
			"baseWork",
			"internalWork",
			"externalWork",
			"rate",
			"subdivisionName" 
			);


	public static List<String> degreeFields = ImmutableList.of(
			"faculty",
			"series",
			"diplomNumber",
			"startEducation",
			"finishEducation",
			"dateOfAssigment",
			"dmn",
			"kmn" 
			);

	public static List<String> internshipFields = ImmutableList.of(
			"faculty",
			"series",
			"diplomNumber",
			"startEducation",
			"finishEducation",
			"internship",
			"traineeship",
			"speciality",
			"targetTraining"
			);

	public static List<String> qualificationFields = ImmutableList.of(
			"organization",
			"nameCycle",
			"whereCompleted",
			"hours",
			"dateTesting",
			"numberCertificate",
			"startEducation",
			"finishEducation",
			"firstQualification"
			);

	public static List<String> quitFields = ImmutableList.of(
			"dateQuit",
			"numberOrder",
			"causeOfQuit",
			"baseWork",
			"internalWork",
			"externalWork"
			);

	public static List<String> retrainingFields = ImmutableList.of(
			"speciality",
			"dateRetraining"
			);

	public static List<String> translationFields = ImmutableList.of(
			"causeOfTranslation",
			"rate",
			"subdivisionName",
			"baseWork",
			"internalWork",
			"externalWork"
			);

	public static List<String> validationFields = ImmutableList.of(
			"assignmentDate",
			"confirmation",
			"firstCategory",
			"secondCategory",
			"higherCategory"
			);

	public static List<String> employeeFields = ImmutableList.of(
			"surname",
			"firstName",
			"secondName",
			"subdivisionName",
			"notes",
			"medicPolic"
			);

	public static List<String> getFiledNamesByType(Class<?> type) {
		switch (type.getSimpleName()) {
		case "Certificate":
			return certificateFields;
		case "AdoptedToStructural":
			return adoptedToStructuralFields;
		case "Degree":
			return degreeFields;
		case "Qualification":
			return qualificationFields;
		case "Quit":
			return quitFields;
		case "Retraining":
			return retrainingFields;
		case "Translation":
			return translationFields;
		case "Validation":
			return validationFields;
		case "Internship":
			return internshipFields;
		default:
			throw new IllegalArgumentException("type " + type + " not found");
		}
	}
	
	
	//TODO Переделать в метод getParam(Class, Field)
	public static List<Object> getParamsByWidgets(List<Pair<String, AbstractWidget<?>>> widgetByName) {
		ArrayList<Object> params = Lists.newArrayList();

		for (Pair<String, AbstractWidget<?>> pair : widgetByName) {
			AbstractWidget<?> widget = pair.getRight();
			params.add(widget.getValue());
		}
		return params;
	}
	
	public static UniqueObject getObjectByWidgets(List<Pair<String, AbstractWidget<?>>> widgetByName, Class<? extends UniqueObject> genericClass) throws Exception {
		UniqueObject instance = genericClass.newInstance();
		UniqueObject internalInstance = null;
		boolean isGeneric = true;
		for (Pair<String, AbstractWidget<?>> pair : widgetByName) {
			AbstractWidget<?> widget = pair.getRight();
			Class<?> fieldType = widget.getFieldType();
			if (!fieldType.equals(instance.getClass())) {
				if (internalInstance != null && !fieldType.equals(internalInstance.getClass())) {
					setSubField(genericClass, instance, internalInstance);
					internalInstance = (UniqueObject) fieldType.newInstance();
				}
				if (isGeneric) {
					internalInstance = (UniqueObject) fieldType.newInstance();
					isGeneric = false;
				}
				widget.setValueForObject(internalInstance);
				continue;
			}
			if (!isGeneric) {
				setSubField(genericClass, instance, internalInstance);
				internalInstance = null;
				isGeneric = true;
			}
			widget.setValueForObject(instance);
		}
		if (internalInstance != null) {
			setSubField(genericClass, instance, internalInstance);
		}
		return instance;
	}

	private static void setSubField(Class<? extends UniqueObject> genericClass, UniqueObject instance, UniqueObject internalInstance) throws IllegalAccessException {
		Field[] fields = genericClass.getDeclaredFields();
		for (Field field : fields) {
			if (field.getType().equals(internalInstance.getClass())) {
				field.setAccessible(true);
				field.set(instance, internalInstance);
				break;
			}
		}
	}
		


}
